﻿using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

internal class ModeBus_RTU
{
    private SerialPort _serialPort;
    public ModeBus_RTU()
    {
        _serialPort = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
        _serialPort.Open();
    }

    // 读取保持寄存器 (功能码 0x03)
    public byte[] ReadHoldingRegisters(byte slaveAddress, ushort startAddress, ushort quantity)
    {
        // 构建请求消息
        byte[] request = new byte[6];
        request[0] = slaveAddress;         // 从站地址
        request[1] = 0x03;                 // 功能码: 读取保持寄存器
        request[2] = (byte)(startAddress >> 8);  // 起始地址高字节
        request[3] = (byte)(startAddress & 0xFF); // 起始地址低字节
        request[4] = (byte)(quantity >> 8);      // 寄存器数量高字节
        request[5] = (byte)(quantity & 0xFF);    // 寄存器数量低字节

        // 添加CRC校验
        byte[] crc = CalculateCrc(request, 6);
        byte[] fullRequest = new byte[8];
        Array.Copy(request, fullRequest, 6);
        Array.Copy(crc, 0, fullRequest, 6, 2);

        // 发送请求并接收响应
        return SendRequest(fullRequest, 5 + (quantity * 2));
    }

    // 写入单个寄存器 (功能码 0x06)
    public byte[] WriteSingleRegister(byte slaveAddress, ushort registerAddress, ushort value)
    {
        // 构建请求消息
        byte[] request = new byte[6];
        request[0] = slaveAddress;                 // 从站地址
        request[1] = 0x06;                         // 功能码: 写入单个寄存器
        request[2] = (byte)(registerAddress >> 8); // 寄存器地址高字节
        request[3] = (byte)(registerAddress & 0xFF); // 寄存器地址低字节
        request[4] = (byte)(value >> 8);              // 值高字节
        request[5] = (byte)(value & 0xFF);            // 值低字节

        // 添加CRC校验
        byte[] crc = CalculateCrc(request, 6);
        byte[] fullRequest = new byte[8];
        Array.Copy(request, fullRequest, 6);
        Array.Copy(crc, 0, fullRequest, 6, 2);

        // 发送请求并接收响应
        return SendRequest(fullRequest, 8);
    }

    // 发送请求并接收响应
    private byte[] SendRequest(byte[] request, int expectedResponseLength)
    {
        try
        {
            // 清空接收缓冲区
            _serialPort.DiscardInBuffer();

            // 发送请求
            _serialPort.Write(request, 0, request.Length);

            // 接收响应
            byte[] response = new byte[256];
            int bytesRead = 0;
            int timeout = 1000;

            while (timeout > 0 && bytesRead < expectedResponseLength)
            {
                if (_serialPort.BytesToRead > 0)
                {
                    int available = _serialPort.BytesToRead;
                    if (bytesRead + available > response.Length)
                    {
                        available = response.Length - bytesRead;
                    }
                    _serialPort.Read(response, bytesRead, available);
                    bytesRead += available;
                }
                else
                {
                    Thread.Sleep(10);
                    timeout -= 10;
                }
            }

            if (bytesRead < 5) { return null; }
            // 复制有效数据
            byte[] responseData = new byte[bytesRead];
            Array.Copy(response, responseData, bytesRead);

            // 验证CRC
            byte[] receivedCrc = new byte[2];
            Array.Copy(responseData, bytesRead - 2, receivedCrc, 0, 2);

            byte[] calculatedCrc = CalculateCrc(responseData, bytesRead - 2);
            if (!receivedCrc.SequenceEqual(calculatedCrc)) { return null; }

            // 检查异常
            if ((responseData[1] & 0x80) != 0)
            {
                Console.WriteLine($"Modbus异常: 功能码={responseData[1] & 0x7F}, 异常码={responseData[2]}");
                return null;
            }

            return responseData;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"通信时出错: {ex.Message}");
            return null;
        }
    }

    // 计算CRC校验
    private byte[] CalculateCrc(byte[] data, int length)
    {
        ushort crc = 0xFFFF;

        for (int i = 0; i < length; i++)
        {
            crc ^= data[i];
            for (int j = 0; j < 8; j++)
            {
                if ((crc & 0x0001) != 0)
                {
                    crc >>= 1;
                    crc ^= 0xA001;
                }
                else
                {
                    crc >>= 1;
                }
            }
        }
        return new byte[] { (byte)(crc & 0xFF), (byte)(crc >> 8) };
    }

    //数据转换
    public List<string> DataTransformation(byte[] response)
    {
        List<string> list = new List<string>();
        if (response != null && response.Length >= 3)
        {
            int byteCount = response[2]; // 数据的字节总数
            for (int i = 0; i < byteCount; i += 2)
            {
                // 拼接高低字节
                ushort registerValue = (ushort)((response[3 + i] << 8) | response[4 + i]);
                list.Add(registerValue.ToString());
            }
        }
        return list;
    }
}
